기말고사
주의: 엑셀 등을 이용하여 자료를 전처리할 경우 부분점수 없이 0점 처리함
1. 시군구별 에너지사용량 시각화 I (30점)
아래의 주소들에서 2018-2021의 시군구별 에너지 사용량에 대한 자료를 정리하고 물음에 답하라.
# 2018
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2018.csv
...
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Jeju-do2018.csv
# 2019
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2019.csv
...
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Jeju-do2019.csv
# 2020
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2020.csv
...
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Jeju-do2020.csv
# 2021
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2021.csv
...
https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Jeju-do2021.csv
hint1: 코드1, 코드2를 적절하게 응용하면 쉽게 데이터를 합칠 수 있음
## 코드1
_district = [global_dict['features'][i]['properties']['name_eng'] for i in range(17)]
_year = ['2018','2019','2020','2021']
for d in _district:
for y in _year:
print(d+y)
## 코드2
_url = 'https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/{}.csv'
pd.concat([pd.read_csv(_url.format(k)) for k in ['Seoul2018','Jeju-do2018']])hint2: 데이터프레임을 읽었을 때 ['에너지사용량(TOE)/지역난방']의 자료형이 통일되어 있지 않음을 유의하여 처리할 것.
pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Gangwon-do2021.csv')['에너지사용량(TOE)/지역난방'].dtypedtype('int64')
pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2021.csv')['에너지사용량(TOE)/지역난방'].dtypedtype('O')
hint3: 아래의 코드를 이용하여 geojson 파일을 확보하고 문제를 풀 것
global_dict = json.loads(requests.get('https://raw.githubusercontent.com/southkorea/southkorea-maps/master/kostat/2018/json/skorea-provinces-2018-geo.json').text)
local_dict = json.loads(requests.get('https://raw.githubusercontent.com/southkorea/southkorea-maps/master/kostat/2018/json/skorea-municipalities-2018-geo.json').text)hint4: 필요하다면 아래의 코드를 활용할 것 (활용하지 않아도 무방함)
| A | B | |
|---|---|---|
| 0 | 서초구 | 33,231 |
| 1 | 강남구 | 22,321 |
| 2 | 송파구 | 45123 |
(할당)
| A | B | C | D | |
|---|---|---|---|---|
| 0 | 서초구 | 33,231 | 2018 | Seoul |
| 1 | 강남구 | 22,321 | 2018 | Seoul |
| 2 | 송파구 | 45123 | 2018 | Seoul |
(인덱스)
| B | C | ||
|---|---|---|---|
| A | D | ||
| 서초구 | Seoul | 33,231 | 2018 |
| 강남구 | Seoul | 22,321 | 2018 |
| 송파구 | Seoul | 45123 | 2018 |
(applymap)
| B | C | ||
|---|---|---|---|
| A | D | ||
| 서초구 | Seoul | 33231 | 2018 |
| 강남구 | Seoul | 22321 | 2018 |
| 송파구 | Seoul | 45123 | 2018 |
(1) 아래의 지역에 대한 4년간 전기 에너지 사용량의 총합을 구하고 folium을 이용하여 시각화 하라.
['Seoul',
'Busan',
'Daegu',
'Incheon',
'Gwangju',
'Daejeon',
'Ulsan',
'Sejongsi',
'Gyeonggi-do',
'Gangwon-do',
'Chungcheongbuk-do',
'Chungcheongnam-do',
'Jeollabuk-do',
'Jeollanam-do',
'Gyeongsangbuk-do',
'Gyeongsangnam-do',
'Jeju-do']
- location = [36,128], zoom_start=7 로 설정
(풀이)
- 단계1: 데이터프레임 정리
df= pd.concat([pd.read_csv(_url.format(d+y)).assign(year=y,district=d) for d in _district_eng for y in _year])\
.reset_index(drop=True)\
.set_axis(['지역local','건물동수','연면적','전기','도시가스','지역난방','연도','지역global'],axis=1)\
.set_index(['지역global','지역local'])\
.applymap(lambda x: int(str(x).replace(',',''))).reset_index()
df| 지역global | 지역local | 건물동수 | 연면적 | 전기 | 도시가스 | 지역난방 | 연도 | |
|---|---|---|---|---|---|---|---|---|
| 0 | Seoul | 종로구 | 17929 | 9141777 | 64818 | 82015 | 111 | 2018 |
| 1 | Seoul | 중구 | 10598 | 10056233 | 81672 | 75260 | 563 | 2018 |
| 2 | Seoul | 용산구 | 17201 | 10639652 | 52659 | 85220 | 12043 | 2018 |
| 3 | Seoul | 성동구 | 14180 | 11631770 | 60559 | 107416 | 0 | 2018 |
| 4 | Seoul | 광진구 | 21520 | 12054796 | 70609 | 130308 | 0 | 2018 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 995 | Jeju-do | 서귀포시 | 34729 | 7233931 | 34641 | 1306 | 0 | 2019 |
| 996 | Jeju-do | 제주시 | 66504 | 19819923 | 99212 | 22179 | 0 | 2020 |
| 997 | Jeju-do | 서귀포시 | 34880 | 7330040 | 35510 | 1639 | 0 | 2020 |
| 998 | Jeju-do | 제주시 | 67053 | 20275738 | 103217 | 25689 | 0 | 2021 |
| 999 | Jeju-do | 서귀포시 | 35230 | 7512206 | 37884 | 2641 | 0 | 2021 |
1000 rows × 8 columns
- 단계2: 시각화할 자료 정리
| 지역global | 전기 | |
|---|---|---|
| 0 | Busan | 2860998 |
| 1 | Chungcheongbuk-do | 1413048 |
| 2 | Chungcheongnam-do | 1795949 |
| 3 | Daegu | 1802007 |
| 4 | Daejeon | 1221429 |
| 5 | Gangwon-do | 1491560 |
| 6 | Gwangju | 1154501 |
| 7 | Gyeonggi-do | 9084472 |
| 8 | Gyeongsangbuk-do | 2045804 |
| 9 | Gyeongsangnam-do | 2450436 |
| 10 | Incheon | 1988226 |
| 11 | Jeju-do | 536540 |
| 12 | Jeollabuk-do | 1416208 |
| 13 | Jeollanam-do | 1341756 |
| 14 | Sejongsi | 263956 |
| 15 | Seoul | 9331349 |
| 16 | Ulsan | 779840 |
- 단계3: 시각화
m = folium.Map(
location = [36,128],
zoom_start=7,
scrollWheelZoom = False
)
folium.Choropleth(
geo_data=global_dict,
data=df.groupby(['지역global'])['전기'].sum().reset_index(),
columns=['지역global','전기'],
key_on='properties.name_eng',
).add_to(m)
m(2) 서울의 4년간 전기에너지 사용량의 총합을 구하고 folium을 이용하여 구별로 시각화 하라.
hint1: 아래의 리스트에서
11로 시작하는 원소들이 서울지역이다.
hint2: 서울특별시의 “중구”는 유일한 구 이름이 아님을 유의하여 자료를 처리할 것. (예를들어 부산에도 “중구”, 대구에도 “중구”가 존재함)
(풀이)
- 단계1: local_dict2 정리
- 단계2: 시각화할 자료정리
| 지역local | 전기 | |
|---|---|---|
| 0 | 강남구 | 905469 |
| 1 | 강동구 | 322585 |
| 2 | 강북구 | 215655 |
| 3 | 강서구 | 438579 |
| 4 | 관악구 | 393429 |
| 5 | 광진구 | 307727 |
| 6 | 구로구 | 326921 |
| 7 | 금천구 | 218396 |
| 8 | 노원구 | 354521 |
| 9 | 도봉구 | 205777 |
| 10 | 동대문구 | 300022 |
| 11 | 동작구 | 298972 |
| 12 | 마포구 | 444166 |
| 13 | 서대문구 | 286668 |
| 14 | 서초구 | 650482 |
| 15 | 성동구 | 300004 |
| 16 | 성북구 | 344506 |
| 17 | 송파구 | 654551 |
| 18 | 양천구 | 339078 |
| 19 | 영등포구 | 459870 |
| 20 | 용산구 | 251535 |
| 21 | 은평구 | 339143 |
| 22 | 종로구 | 313612 |
| 23 | 중구 | 394690 |
| 24 | 중랑구 | 264991 |
- 단계3: 시각화
m = folium.Map(
location = [37.55,127],
zoom_start=11,
scrollWheelZoom = False
)
folium.Choropleth(
geo_data=local_dict2,
data=df.query('지역global=="Seoul"').groupby('지역local')['전기'].sum().reset_index(),
columns=['지역local','전기'],
key_on='properties.name',
).add_to(m)
m- location = [37.55,127], zoom_start=11 로 설정
(3) 서울의 전기에너지 사용비율을 (연도별,구별)로 구하고 이를 plotly의 choropleth_mapbox를 이용하여 시각화 하라. (연도에 따라 choropleth map이 바뀌도록 시각화 할 것)
hint1: 2020년의 관악구의 전기에너지 사용비율은 아래와 같이 계산한다.
\(\frac{\text{2020관악구의 ``에너지사용량(TOE)/전기''}}{\text{2020관악구의 ``에너지사용량(TOE)/전기''}+\text{2020관악구의 ``에너지사용량(TOE)/도시가스''}+\text{2020년 관악구의 ``에너지사용량(TOE)/지역난방''}}\)
hint2: 아래의 코드 참고할 것.
fig = px.choropleth_mapbox(data_frame=???,
geojson=???,
color=???,
locations=???,
featureidkey=???,
center={"lat": 37.55, "lon": 126.95},
mapbox_style="carto-positron",
animation_frame=???, # 2028,2019,2020,2021와 같이 년도가 명시된 column의 이름을 쓸 것
range_color=[0.31,0.56],
height=800,
zoom=10)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})(풀이)
- 1단계: 시각화할 자료정리
| 지역global | 지역local | 건물동수 | 연면적 | 전기 | 도시가스 | 지역난방 | 연도 | 전기사용비율 | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | Seoul | 종로구 | 17929 | 9141777 | 64818 | 82015 | 111 | 2018 | 0.441107 |
| 1 | Seoul | 중구 | 10598 | 10056233 | 81672 | 75260 | 563 | 2018 | 0.518569 |
| 2 | Seoul | 용산구 | 17201 | 10639652 | 52659 | 85220 | 12043 | 2018 | 0.351243 |
| 3 | Seoul | 성동구 | 14180 | 11631770 | 60559 | 107416 | 0 | 2018 | 0.360524 |
| 4 | Seoul | 광진구 | 21520 | 12054796 | 70609 | 130308 | 0 | 2018 | 0.351434 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 95 | Seoul | 관악구 | 31299 | 22230193 | 136043 | 196643 | 78 | 2021 | 0.408827 |
| 96 | Seoul | 서초구 | 16686 | 32824535 | 242700 | 181974 | 39854 | 2021 | 0.522466 |
| 97 | Seoul | 강남구 | 22464 | 48871036 | 364645 | 236446 | 95742 | 2021 | 0.523289 |
| 98 | Seoul | 송파구 | 22727 | 38819901 | 236444 | 185492 | 94175 | 2021 | 0.458126 |
| 99 | Seoul | 강동구 | 18715 | 24990185 | 110313 | 144513 | 16676 | 2021 | 0.406306 |
100 rows × 9 columns
- 2단계: 시각화
fig = px.choropleth_mapbox(data_frame=df.eval('전기사용비율 = 전기/(전기+도시가스+지역난방)').query('지역global=="Seoul"'),
geojson=local_dict2,
color='전기사용비율',
locations="지역local",
featureidkey="properties.name",
center={"lat": 37.55, "lon": 127},
mapbox_style="carto-positron",
animation_frame='연도',
range_color=[0.31,0.56],
height=800,
zoom=10)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})2. 시군구별 에너지사용량 시각화 II (50점)
문제1과 동일한 자료에 대하여 아래의 물음에 답하라.
(1) 전주시 덕진구와 완산구에서 사용하는 전기양은 전라북도 전체의 몇 프로인지 연도별로 계산하고 아래의 예시와 같이 시각화 하라.
(풀이)
- 단계1: 시각화할 자료 정리
data = df.query('지역global=="Jeollabuk-do"')\
.groupby(['연도'])[['전기']].sum().reset_index()\
.rename({'전기':'전라북도전기'},axis=1)\
.merge(df.query('지역global=="Jeollabuk-do"'))\
.eval("전기사용비율=전기/전라북도전기")\
.query('지역local == "덕진구" or 지역local == "완산구"')\
.assign(전기사용비율 = lambda df: np.round(df['전기사용비율']*100,2))
data NameError: name 'df' is not defined
- 단계2: 시각화
NameError: name 'data' is not defined
(2) 면적대비 총 에너지사용량이 많은 상위20개의 지역을 찾고 아래의 예시와 같이 시각화 하라.
(풀이)
- 단계1: 시각화할 자료 정리
data = df.eval('면적대비에너지사용량 = (전기+도시가스+지역난방)/ 연면적')\
.assign(면적대비에너지사용량 = lambda df: list(map(lambda x: np.round(x,4),df['면적대비에너지사용량'])))\
.sort_values(by='면적대비에너지사용량',ascending=False).reset_index(drop=True).iloc[:20]\
.assign(지역연도=lambda df: list(map(lambda x,y: x+'/'+str(y), df['지역local'],df['연도'])))\
.rename({'지역연도':'지역/연도'},axis=1)
dataNameError: name 'df' is not defined
서울특별시와 경기도에 속한 구역을 아래와 같이 구분하여 시각화 하라.
NameError: name 'data' is not defined
(3) 각 시도별로 4년간 에너지사용량(=전기+도시가스+지역난방)이 가장 많은 2개의 구를 뽑고 아래와 같이 시각화 하라.
(풀이)
- 단계1: 에너지사용량을 계산
- 단계2: 4년간 에너지사용량을 구함
df.eval('에너지사용량=전기+도시가스+지역난방')\
.groupby(['지역local','지역global'])\
.agg({'에너지사용량':np.sum}).reset_index().rename({'에너지사용량':'4년간에너지사용량'},axis=1)NameError: name 'df' is not defined
- 단계3: ’지역global’로 그룹핑된 리스트 생성
lst = df.eval('에너지사용량=전기+도시가스+지역난방')\
.groupby(['지역local','지역global'])\
.agg({'에너지사용량':np.sum}).reset_index().rename({'에너지사용량':'4년간에너지사용량'},axis=1)\
.groupby('지역global')\
.pipe(list)
lst[0] # 편의상 리스트의 첫원소만 출력 NameError: name 'df' is not defined
- 단계4: 단계3의 결과를 이용하여 4년간에너지사용량이 가장 큰 2개의 구만 선택
data = pd.concat(list(map(lambda x: x[1].sort_values(by='4년간에너지사용량',ascending=False).reset_index(drop=True).iloc[:2],lst))).reset_index(drop=True)
dataNameError: name 'pd' is not defined
- 단계5: 시각화
NameError: name 'data' is not defined
(4) ‘Seoul’, ‘Incheon’, ‘Gyeonggi-do’ 지역을 수도권으로 그 외의 지역은 비수도권으로 구분하라.
(풀이)
- 단계1: 시각화를 위한 데이터정리
data= df.assign(MetropolitanArea=list(map(lambda x: x in ['Seoul', 'Incheon', 'Gyeonggi-do'],df['지역global'])))\
.rename({'전기':'Elec','도시가스':'Gas','연도':'Year'},axis=1)\
.loc[:,['Elec','Gas','Year','MetropolitanArea']]\
.set_index(['Year','MetropolitanArea'])\
.stack()\
.reset_index()\
.rename({'level_2':'EnergyType',0:'Consumption'},axis=1)
dataNameError: name 'df' is not defined
- 단계2: 시각화
3. 심슨의 역설 (20점)
아래는 1973년 가을학기 버클리대학의 입학통계이다.
pd.read_csv("https://raw.githubusercontent.com/guebin/DV2022/master/posts/Simpson.csv",index_col=0,header=[0,1])NameError: name 'pd' is not defined
(1) 남녀합격률을 plotly를 사용하여 시각화 하라.
(풀이)
- 단계0: 강의노트와 동일한 방식으로 df, data 생성
df=pd.read_csv("https://raw.githubusercontent.com/guebin/DV2022/master/posts/Simpson.csv",index_col=0,header=[0,1])\
.stack().stack().reset_index()\
.rename({'level_0':'department','level_1':'result','level_2':'gender',0:'count'},axis=1)
df.head()NameError: name 'pd' is not defined
data= df.groupby(['gender','result']).agg({'count':np.sum}).reset_index()\
.merge(df.groupby('gender').agg({'count':np.sum}).reset_index().rename({'count':'count2'},axis=1))\
.eval('rate = count/count2').query('result=="pass"')
data.head()NameError: name 'df' is not defined
- 단계1: 소수점처리
- 단계2: 시각화
data.assign(rate = np.round(data['rate']*100,2))\
.plot.bar(backend='plotly',y='gender',x='rate',color='gender',barmode='group',text='rate')NameError: name 'data' is not defined
(2) 학과별 남녀합격률을 plotly를 사용하여 시각화 하라.
(풀이)
- 단계0: 강의노트와 동일한 방식으로 data2 생성
data2=df.merge(df.groupby(['department','gender']).agg({'count':np.sum}).reset_index().rename({'count':'count2'},axis=1))\
.eval('rate = count/count2').query('result=="pass"')
data2NameError: name 'df' is not defined
- 단계1: 시각화